package se.cbb.scripts;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

import se.cbb.misc.Couple;
import se.cbb.misc.SequenceFileWriter;

public class ConvertDistMatrixToNewick {

	public static void main(String[] args) {
		String path = "/Users/rhali/Documents/Projects/GrandOrthology/";
		String fileName = path + "Dist_Matrix_From_LCA.txt";
		BufferedReader bufferedreader;
		String str;
		String[][] distMatrix = new String[69][69];
		int index = 0;

		try {
			bufferedreader = new BufferedReader(new FileReader(fileName));
			while ((str = bufferedreader.readLine()) != null) {
				String[] strArr = str.split("\t");
				for(int i = 0; i < strArr.length; i++) {
					distMatrix[index][i] = strArr[i];
				}
				index++;
			}
			bufferedreader.close();
		} catch (Exception e) {
			System.out.println("Error : " + e.getMessage());
		}

		for(int l = 1; l < 21784; l++) {
			try{
//				System.out.println("Running : " + l);
				bufferedreader = new BufferedReader(new FileReader(path + "Mapping/Mapping" + l + ".map"));
				ArrayList<String> spec = new ArrayList<String>();
				while ((str = bufferedreader.readLine()) != null) {
					String[] strArr = str.split("\t");
					boolean exists = false;
					for (int i = 0; i < spec.size(); i++) {
						if(strArr[1].equals(spec.get(i))) {
							exists = true;
						}
					}
					if(exists == false) {
						spec.add(strArr[1]);
					}
				}
				bufferedreader.close();

				String[][] finalDistMatrix = new String[spec.size() + 1][spec.size() + 1];
				finalDistMatrix[0][0] = "";
				for(int i = 0; i < spec.size(); i++) {
					finalDistMatrix[0][i+1] = spec.get(i);
					finalDistMatrix[i+1][0] = spec.get(i);
					int xIndex = -1;
					for(int j = 0; j < distMatrix[0].length; j++) {
						if(distMatrix[j][0].equals(spec.get(i))) {
							xIndex = j;
							break;
						}
					}

					if(xIndex == -1)
						System.out.println("jejeje " + spec.get(i));

					for(int k = 0; k < i; k++) {
						int yIndex = -1;
						for(int j = 0; j < distMatrix[0].length; j++) {
							if(distMatrix[0][j].equals(spec.get(k))) {
								yIndex = j;
								break;
							}
						}

						if(yIndex == -1) {
							System.out.println("----------------------" + spec.get(k));
						}
						finalDistMatrix[i+1][k+1] = distMatrix[xIndex][yIndex];
						finalDistMatrix[k+1][i+1] = distMatrix[xIndex][yIndex];
						if(!distMatrix[0][yIndex].equals(finalDistMatrix[0][k+1]))
							System.out.println(distMatrix[0][yIndex] + "\t" + finalDistMatrix[0][k+1]);
						if(!distMatrix[xIndex][0].equals(finalDistMatrix[i+1][0]))
							System.out.println(finalDistMatrix[i+1][0] + "\t" + finalDistMatrix[i+1][0]);
					}
					finalDistMatrix[i+1][i+1] = "0";
				}
				
				Double rootDistance = determineRoot(distMatrix, spec);
				
				if(rootDistance > 1881.09) 
					rootDistance = 1881.09;

				ConvertDistMatrixToNewick temp = new ConvertDistMatrixToNewick();
				for( int i = 1; i < finalDistMatrix[0].length; i++) {
					Couple<Integer, Integer> coord = temp.determineminforRow(finalDistMatrix, i);
					finalDistMatrix[0][i] = finalDistMatrix[0][i] + ":" + finalDistMatrix[coord.first][coord.second];
					finalDistMatrix[i][0] = finalDistMatrix[0][i];
				}

				String newicktemp = temp.determineNewick(finalDistMatrix) + ":" + rootDistance + ";";
				System.out.println(newicktemp);

				String[] strArr = newicktemp.split(":");
				String newick = "";

				for(int i = 0; i < strArr.length; i++) {
					if(strArr[i].endsWith(")")) {
						String Double1 = "";
						int j = 0;
						while(strArr[i].charAt(j) == '.' || strArr[i].charAt(j) == '0' || strArr[i].charAt(j) == '1' || strArr[i].charAt(j) == '2' || strArr[i].charAt(j) == '3' || strArr[i].charAt(j) == '4' || strArr[i].charAt(j) == '5' || strArr[i].charAt(j) == '6' || strArr[i].charAt(j) == '7' || strArr[i].charAt(j) == '8' || strArr[i].charAt(j) == '9') {
							Double1 = Double1 + strArr[i].substring(j, j+1);
							j++;
						}

						String Double2 = "";
						int k = 0;
						while(strArr[i+1].charAt(k) == '.' || strArr[i+1].charAt(k) == '0' || strArr[i+1].charAt(k) == '1' || strArr[i+1].charAt(k) == '2' || strArr[i+1].charAt(k) == '3' || strArr[i+1].charAt(k) == '4' || strArr[i+1].charAt(k) == '5' || strArr[i+1].charAt(k) == '6' || strArr[i+1].charAt(k) == '7' || strArr[i+1].charAt(k) == '8' || strArr[i+1].charAt(k) == '9') {
							Double2 = Double2 + strArr[i+1].substring(k, k+1);
							k++;
						}

						String res = String.valueOf(Math.round((Double.parseDouble(Double2) - Double.parseDouble(Double1))*100.0)/100.0);
						if(newick.endsWith("0") || newick.endsWith("1") || newick.endsWith("2") || newick.endsWith("3") || newick.endsWith("4") || newick.endsWith("5") || newick.endsWith("6") || newick.endsWith("7") || newick.endsWith("8") || newick.endsWith("9"))
							newick = newick + "):" + res;	
						else
							newick = newick + strArr[i] + ":" + res;
					} else {
						if(newick.endsWith("0") || newick.endsWith("1") || newick.endsWith("2") || newick.endsWith("3") || newick.endsWith("4") || newick.endsWith("5") || newick.endsWith("6") || newick.endsWith("7") || newick.endsWith("8") || newick.endsWith("9")) {
							int k = 0;
							while(strArr[i].charAt(k) == '.' || strArr[i].charAt(k) == '0' || strArr[i].charAt(k) == '1' || strArr[i].charAt(k) == '2' || strArr[i].charAt(k) == '3' || strArr[i].charAt(k) == '4' || strArr[i].charAt(k) == '5' || strArr[i].charAt(k) == '6' || strArr[i].charAt(k) == '7' || strArr[i].charAt(k) == '8' || strArr[i].charAt(k) == '9') {
								k++;
							}
							newick = newick + strArr[i].substring(k) + ":";
						} else
							newick = newick + strArr[i] + ":"; 
					}
				}
				SequenceFileWriter.writeAndAppendLine(path + "SpeciesTrees/", "Species_tree" + l + ".nwk", newick.substring(0, newick.length()-1));
			} catch (Exception e) {
				System.out.println("E:" + l);
			}
		} 
	}
	
	public static Double determineRoot(String[][] distMatrix, ArrayList<String> spec) {
		String species = spec.get(0);
		int index = -1;
		for(int i = 0; i < distMatrix[0].length; i++) {
			if(species.equals(distMatrix[0][i]))  {
				index = i;
				break;
			}
		}
		
		Double maximum = (double) -1; 
		for(int i = 1; i < distMatrix[0].length; i++) {
			if(spec.contains(distMatrix[0][i]) && Double.parseDouble(distMatrix[index][i]) > maximum) {
				maximum = Double.parseDouble(distMatrix[index][i]);
			}
		}
		
		Double minimum = 10000.0; 
		for(int i = 1; i < distMatrix[0].length; i++) {
			if(!spec.contains(distMatrix[0][i]) && Double.parseDouble(distMatrix[index][i]) < minimum && Double.parseDouble(distMatrix[index][i]) > maximum) {
				minimum = Double.parseDouble(distMatrix[index][i]);
			}
		}
		return minimum;
	}

	public String determineNewick(String[][] finalDistMatrix) {
		if(finalDistMatrix[0].length < 3) {
			return finalDistMatrix[0][1];
		} else {
			String[][] finalDistMatrix1 = new String[finalDistMatrix[0].length -1][finalDistMatrix[0].length -1];
			finalDistMatrix1[0][0] = "";

			Couple<Integer, Integer> coord = determinemin(finalDistMatrix);
			if(coord.first > coord.second)
				coord = new Couple<Integer, Integer>(coord.second, coord.first);

			if(finalDistMatrix[coord.first][0].startsWith("(") && finalDistMatrix[0][coord.second].startsWith("(")) 
				finalDistMatrix1[coord.first][0] = "(" + finalDistMatrix[coord.first][0] + ":" + finalDistMatrix[coord.first][coord.second] + "," + finalDistMatrix[0][coord.second] + ":" + finalDistMatrix[coord.first][coord.second] + ")";
			else if(finalDistMatrix[coord.first][0].startsWith("(") && !finalDistMatrix[0][coord.second].startsWith("(")) 
				finalDistMatrix1[coord.first][0] = "(" + finalDistMatrix[coord.first][0] + ":" + finalDistMatrix[coord.first][coord.second] + "," + finalDistMatrix[0][coord.second] + ")";
			else if(!finalDistMatrix[coord.first][0].startsWith("(") && finalDistMatrix[0][coord.second].startsWith("(")) 
				finalDistMatrix1[coord.first][0] = "(" + finalDistMatrix[coord.first][0] + "," + finalDistMatrix[0][coord.second] + ":" + finalDistMatrix[coord.first][coord.second] + ")";
			else if(!finalDistMatrix[coord.first][0].startsWith("(") && !finalDistMatrix[0][coord.second].startsWith("(")) 
				finalDistMatrix1[coord.first][0] = "(" + finalDistMatrix[coord.first][0] + "," + finalDistMatrix[0][coord.second] + ")";
			finalDistMatrix1[0][coord.first] = finalDistMatrix1[coord.first][0];

			for(int i = 1; i < finalDistMatrix1[0].length; i++) {
				if(i == coord.first)
					continue;
				else if(i < coord.second) {
					finalDistMatrix1[0][i] = finalDistMatrix[0][i];
					finalDistMatrix1[i][0] = finalDistMatrix[0][i];
				} else if(i >= coord.second) {
					finalDistMatrix1[0][i] = finalDistMatrix[0][i+1];
					finalDistMatrix1[i][0] = finalDistMatrix[0][i+1];
				}
			}

			for(int i = 1; i < finalDistMatrix1[0].length; i++) {
				if(i == coord.first) {
					for(int j = 1; j < finalDistMatrix1[0].length; j++) {
						if(i != j) {
							if(j < coord.second) {
								finalDistMatrix1[i][j] = String.valueOf(Double.parseDouble(finalDistMatrix[i][j]));
								finalDistMatrix1[j][i] = finalDistMatrix1[i][j];
							} else if(j >= coord.second) {
								finalDistMatrix1[i][j] = String.valueOf(Double.parseDouble(finalDistMatrix[i][j+1]));
								finalDistMatrix1[j][i] = finalDistMatrix1[i][j];
							}

						}
					}
				} else if(i < coord.second) {
					for(int j = 1; j < finalDistMatrix1[0].length; j++) {
						if(j==coord.first)
							continue;
						else if(j<coord.second) {
							finalDistMatrix1[j][i] = finalDistMatrix[j][i];
							finalDistMatrix1[i][j] = finalDistMatrix[j][i];
						} else if (j >= coord.second) {
							finalDistMatrix1[j][i] = finalDistMatrix[j+1][i];
							finalDistMatrix1[i][j] = finalDistMatrix[j+1][i];
						}
					}
				} else if(i >= coord.second) {
					for(int j = 1; j < finalDistMatrix1[0].length; j++) {
						if(j==coord.first)
							continue;
						else if(j<coord.second) {
							finalDistMatrix1[j][i] = finalDistMatrix[j][i + 1];
							finalDistMatrix1[i][j] = finalDistMatrix[j][i + 1];
						} else if (j >= coord.second) {
							finalDistMatrix1[j][i] = finalDistMatrix[j + 1][i + 1];
							finalDistMatrix1[i][j] = finalDistMatrix[j + 1][i + 1];
						}
					}
				}
			}

			for(int i = 1; i < finalDistMatrix1[0].length; i++) {
				for(int j = 1; j < i; j++) {
					if(coord.second > i) {
						if(i != coord.first && j != coord.first) {
							finalDistMatrix1[i][j] = finalDistMatrix[i][j];
							finalDistMatrix1[j][i] = finalDistMatrix1[i][j];
						}
					} else {
						if (j == coord.first || i == coord.second || j == coord.first)
							continue;
						if(j < coord.second)
							finalDistMatrix1[i][j] = finalDistMatrix[i+1][j];
						else
							finalDistMatrix1[i][j] = finalDistMatrix[i+1][j+1];
					}
				}
				finalDistMatrix1[i][i] = "0";
			}
			return determineNewick(finalDistMatrix1);
		}
	}

	public Couple<Integer, Integer> determinemin(String[][] finalDistMatrix) {
		int xcoord = -1;
		int ycoord = -1;
		Double min = 10000.0;
		for(int i = 1; i < finalDistMatrix[0].length; i++) {
			for(int j = 1; j < i; j++) {
				if(Double.parseDouble(finalDistMatrix[i][j]) < min) {
					min = Double.parseDouble(finalDistMatrix[i][j]);
					xcoord = i;
					ycoord = j;
				}
			}
		}

		Couple<Integer, Integer> coord = new Couple<Integer, Integer>(xcoord,ycoord);
		return coord;
	}

	public Couple<Integer, Integer> determineminforRow(String[][] finalDistMatrix, int row) {
		int ycoord = -1;
		Double min = 10000.0;
		for(int j = 1; j < finalDistMatrix[0].length; j++) {
			if(Double.parseDouble(finalDistMatrix[row][j]) < min && j != row) {
				min = Double.parseDouble(finalDistMatrix[row][j]);
				ycoord = j;
			}
		}

		Couple<Integer, Integer> coord = new Couple<Integer, Integer>(row,ycoord);
		return coord;
	}
}
